import type { AxiosError, AxiosInstance, AxiosProgressEvent, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import type { MyRequestConfig } from './helpers'
import { useUserStoreWithOut } from '@/store/modules/user'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { set } from 'lodash-es'
import qs from 'qs'
import { ContentType } from './helpers'

export const errorCode = {
  400: '参数传递不符合接口规范',
  401: '认证失败，无法访问系统资源，即将跳转到登录页面...',
  403: '当前操作没有权限',
  404: '访问资源不存在',
  500: '系统服务错误',
  default: '系统未知错误',
  append: '请反馈给管理员',
}

export const baseURL = import.meta.env.DEV ? import.meta.env.VITE_APP_BASE_API_PROXY : import.meta.env.VITE_APP_BASE_API

const abortControllerMap: Map<string, AbortController> = new Map()

const axiosInstance: AxiosInstance = axios.create({
  baseURL,
  timeout: 60 * 1000, // TODO 测试完之后设置合理的接口等待时间
})

axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  const controller = new AbortController()
  const url = config.url || ''
  config.signal = controller.signal
  abortControllerMap.set(url, controller)
  configureHeaders(config)
  configureQs(config)
  configureBlob(config)
  // openLoading()
  return config
})

axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    const url = response.config.url || ''
    abortControllerMap.delete(url)
    // closeLoading()
    // 如果后端的401等报错返回的status为200，而是在responseData中返回了相应的报错code，那么这里就需要额外处理错误
    // 如果不存在上述情况，下面代码可注释掉
    // #region 相关处理 ********************************************************************************
    const errorMessage
      = ((response.data as any)?.msg
        ?? (response.data as any)?.message
        ?? (response.data as any)?.resMessage // 新一代项目中定义的错误信息
        ?? errorCode.default) + errorCode.append
    const code = response.data.code ?? response.data.resCode // 新一代项目中定义的错误码
    if (code) {
      switch (code) {
        case 200:
          return response
        case 404:
          ElMessage.error(errorCode['404'])
          return Promise.reject(response)
        case 403:
          ElMessage.error(errorCode['403'])
          return Promise.reject(response)
        case 500:
          ElMessage.error(errorMessage)
          return Promise.reject(response)
        case 401:
          ElMessage.error({
            message: errorCode['401'],
            onClose: () => {
              // TODO 清除缓存并跳转到重新登录页面
            },
          })
          return Promise.reject(response)
        //  // 新一代项目中定义的错误码
        case '9999':
          ElMessage.error(errorMessage)
          return Promise.reject(response)
      }
    }
    // #endregion *************************************************************************************
    return response
  },
  (error: AxiosError) => {
    // closeLoading()
    if (error.response) {
      const errorMessage = ((error.response.data as any)?.msg ?? (error.response.data as any)?.message ?? errorCode.default) + errorCode.append
      const code = error.response.status
      switch (code) {
        case 404:
          ElMessage.error(errorCode['404'])
          break
        case 403:
          ElMessage.error(errorCode['403'])
          break
        case 400:
          ElMessage.error(errorCode['400'])
          break
        case 500:
          ElMessage.error(errorMessage)
          break
        case 401:
          ElMessage.error({
            message: errorCode['401'],
            onClose: () => {
              // TODO 清除缓存并跳转到重新登录页面
            },
          })
          break
        default:
          ElMessage.error(errorMessage)
          break
      }
    }
    else {
      ElMessage.error(error.message)
    }
    return Promise.reject(error)
  },
)

const service = {
  request: <T = any>(config: MyRequestConfig) => {
    return axiosInstance.request<T>(config)
  },
  cancelRequest: (url: string | string[]) => {
    const urlList = Array.isArray(url) ? url : [url]
    for (const _url of urlList) {
      abortControllerMap.get(_url)?.abort()
      abortControllerMap.delete(_url)
    }
  },
  cancelAllRequest() {
    for (const [_, controller] of abortControllerMap) controller.abort()

    abortControllerMap.clear()
  },
}

// 配置headers
function configureHeaders(config: AxiosRequestConfig) {
  if (!config.headers?.['Content-Type'])
    set(config, ['headers', 'Content-Type'], ContentType.JSON)
  const userStore = useUserStoreWithOut()
  if (userStore.getToken)
    set(config, 'headers.Authorization', userStore.getToken)
}

// 配置 GET 请求传参
function configureQs(config: AxiosRequestConfig) {
  if (config.method?.toLowerCase() === 'get') {
    config.paramsSerializer = params => qs.stringify(params, { arrayFormat: 'repeat' })
  }

  if (config.headers?.['Content-Type'] === ContentType.FORM_URLENCODED && typeof config.data !== 'string') {
    config.data = qs.stringify(config.data)
  }
}

// 处理blob下载进度
function configureBlob(config: AxiosRequestConfig) {
  if (config.responseType === 'blob' && !config.onDownloadProgress) {
    config.onDownloadProgress = function (progressEvent: AxiosProgressEvent) {
      const { loaded, total } = progressEvent
      if (total && loaded) {
        const percent = Math.round((loaded / total) * 100)
        console.log(`Downloading progress: ${percent}%`)
        return new Promise(resolve => setTimeout(resolve, 100)) // 每 100 毫秒更新一次下载进度
      }
    }
  }
}

export { axiosInstance, service, service as default }
